home *** CD-ROM | disk | FTP | other *** search
/ MacHack 1997 / MacHack 1997.toast / Hacks / Hacks ’97 / Finder Dungeon / source code / MoreFiles 1.4.6 / Sources / FSpCompat.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-06-28  |  25.7 KB  |  938 lines  |  [TEXT/MPS ]

  1. /*
  2. **    Apple Macintosh Developer Technical Support
  3. **
  4. **    FSSpec compatibility functions.
  5. **
  6. **    by Jim Luther, Apple Developer Technical Support Emeritus
  7. **
  8. **    File:        FSpCompat.c
  9. **
  10. **    Copyright © 1992-1996 Apple Computer, Inc.
  11. **    All rights reserved.
  12. **
  13. **    You may incorporate this sample code into your applications without
  14. **    restriction, though the sample code has been provided "AS IS" and the
  15. **    responsibility for its operation is 100% yours.  However, what you are
  16. **    not permitted to do is to redistribute the source as "DSC Sample Code"
  17. **    after having made changes. If you're going to re-distribute the source,
  18. **    we require that you make it clear in the source that the code was
  19. **    descended from Apple Sample Code, but that you've made changes.
  20. */
  21.  
  22. /*
  23. **    If building application 68K code, set GENERATENODATA to 0 for faster code.
  24. **    If building stand-alone 68K code, set GENERATENODATA to 1 so globals
  25. **        (static variables) are not used.
  26. */
  27. #ifndef GENERATENODATA
  28. #define GENERATENODATA 0
  29. #endif
  30.  
  31. #include <Types.h>
  32. #include <Errors.h>
  33. #include <LowMem.h>
  34. #include <Gestalt.h>
  35. #include <Resources.h>
  36. #include <Script.h>
  37.  
  38. #define    __COMPILINGMOREFILES
  39.  
  40. #include "MoreFilesExtras.h"
  41. #include "FSpCompat.h"
  42.  
  43. /*****************************************************************************/
  44.  
  45. /* local constants */
  46.  
  47. enum {
  48.     gestaltBugFixAttrsTwo                    = 'bugy',
  49.     gestaltFSpExchangeFilesCompatibilityFix    = 26,
  50.     gestaltBugFixAttrsThree                    = 'bugx',
  51.     gestaltFSpCreateScriptSupportFix        = 1
  52. };
  53.  
  54. /*****************************************************************************/
  55.  
  56. /* static prototypes */
  57.  
  58.  
  59. #if !SystemSevenOrLater
  60. static    Boolean    FSHasFSSpecCalls(void);
  61.  
  62. static    Boolean    QTHasFSSpecCalls(void);
  63. #endif    /* !SystemSevenOrLater */
  64.  
  65. #if !SystemSevenFiveOrLater
  66. static    Boolean    HasFSpExchangeFilesCompatibilityFix(void);
  67. #endif    /* !SystemSevenFiveOrLater */
  68.  
  69. static    Boolean    HasFSpCreateScriptSupportFix(void);
  70.  
  71. #if !SystemSevenFiveOrLater
  72. static    OSErr    GenerateUniqueName(short volume,
  73.                                    long *startSeed,
  74.                                    long dir1,
  75.                                    long dir2,
  76.                                    StringPtr uniqueName);
  77. #endif    /* !SystemSevenFiveOrLater */
  78.  
  79. /*****************************************************************************/
  80.  
  81. /* FSHasFSSpecCalls returns true if the file system provides FSSpec calls. */
  82.  
  83. #if !SystemSevenOrLater
  84. static    Boolean    FSHasFSSpecCalls(void)
  85. {
  86.     long            response;
  87. #if !GENERATENODATA
  88.     static Boolean    tested = false;
  89.     static Boolean    result = false;
  90. #else
  91.     Boolean    result = false;
  92. #endif
  93.     
  94. #if !GENERATENODATA
  95.     if ( !tested )
  96.     {
  97.         tested = true;
  98. #endif
  99.         if ( Gestalt(gestaltFSAttr, &response) == noErr )
  100.         {
  101.             result = ((response & (1L << gestaltHasFSSpecCalls)) != 0);
  102.         }
  103. #if !GENERATENODATA
  104.     }
  105. #endif
  106.     return ( result );
  107. }
  108. #endif    /* !SystemSevenOrLater */
  109.  
  110. /*****************************************************************************/
  111.  
  112. /* QTHasFSSpecCalls returns true if QuickTime provides FSSpec calls */
  113. /* except for FSpExchangeFiles. */
  114.  
  115. #if !SystemSevenOrLater
  116. static    Boolean    QTHasFSSpecCalls(void)
  117. {
  118.     long            response;
  119. #if !GENERATENODATA
  120.     static Boolean    tested = false;
  121.     static Boolean    result = false;
  122. #else
  123.     Boolean    result = false;
  124. #endif
  125.     
  126. #if !GENERATENODATA
  127.     if ( !tested )
  128.     {
  129.         tested = true;
  130. #endif
  131.         result = (Gestalt(gestaltQuickTimeVersion, &response) == noErr);
  132. #if !GENERATENODATA
  133.     }
  134. #endif
  135.     return ( result );
  136. }
  137. #endif    /* !SystemSevenOrLater */
  138.  
  139. /*****************************************************************************/
  140.  
  141. /* HasFSpExchangeFilesCompatibilityFix returns true if FSpExchangeFiles */
  142. /* compatibility code has been fixed in system software. */
  143. /* This was fixed by System Update 3.0, so if SystemSevenFiveOrLater */
  144. /* is true, then we know the fix is in. */
  145.  
  146. #if !SystemSevenFiveOrLater
  147. static    Boolean    HasFSpExchangeFilesCompatibilityFix(void)
  148. {
  149.     long            response;
  150. #if !GENERATENODATA
  151.     static Boolean    tested = false;
  152.     static Boolean    result = false;
  153. #else    /* !GENERATENODATA */
  154.     Boolean    result = false;
  155. #endif    /* !GENERATENODATA */
  156.     
  157. #if !GENERATENODATA
  158.     if ( !tested )
  159.     {
  160.         tested = true;
  161. #endif    /* !GENERATENODATA */
  162.         if ( Gestalt(gestaltBugFixAttrsTwo, &response) == noErr )
  163.         {
  164.             result = ((response & (1L << gestaltFSpExchangeFilesCompatibilityFix)) != 0);
  165.         }
  166. #if !GENERATENODATA
  167.     }
  168. #endif    /* !GENERATENODATA */
  169.     return ( result );
  170. }
  171. #endif    /* !SystemSevenFiveOrLater */
  172.  
  173. /*****************************************************************************/
  174.  
  175. /* HasFSpCreateScriptSupportFix returns true if FSpCreate and */
  176. /* FSpCreateResFile have been fixed in system software to correctly set */
  177. /* the scriptCode in the volume's catalog. */
  178. /* This was fixed by System 7.5 Update 1.0 */
  179.  
  180. static    Boolean    HasFSpCreateScriptSupportFix(void)
  181. {
  182.     long            response;
  183. #if !GENERATENODATA
  184.     static Boolean    tested = false;
  185.     static Boolean    result = false;
  186. #else
  187.     Boolean    result = false;
  188. #endif    /* !GENERATENODATA */
  189.     
  190. #if !GENERATENODATA
  191.     if ( !tested )
  192.     {
  193.         tested = true;
  194. #endif    /* !GENERATENODATA */
  195.         if ( Gestalt(gestaltBugFixAttrsThree, &response) == noErr )
  196.         {
  197.             result = ((response & (1L << gestaltFSpCreateScriptSupportFix)) != 0);
  198.         }
  199. #if !GENERATENODATA
  200.     }
  201. #endif    /* !GENERATENODATA */
  202.     return ( result );
  203. }
  204.  
  205. /*****************************************************************************/
  206.  
  207. /*
  208. **    File Manager FSp calls
  209. */
  210.  
  211. /*****************************************************************************/
  212.  
  213. pascal    OSErr    FSMakeFSSpecCompat(short vRefNum,
  214.                                    long dirID,
  215.                                    ConstStr255Param fileName,
  216.                                    FSSpec *spec)
  217. {
  218.     OSErr    result;
  219.     
  220. #if !SystemSevenOrLater
  221.     if ( FSHasFSSpecCalls() || QTHasFSSpecCalls() )
  222. #endif    /* !SystemSevenOrLater */
  223.     {
  224.         /* Let the file system create the FSSpec if it can since it does the job */
  225.         /* much more efficiently than I can. */
  226.         result = FSMakeFSSpec(vRefNum, dirID, fileName, spec);
  227.         /* Fix a bug in Macintosh PC Exchange's MakeFSSpec code where 0 is */
  228.         /* returned in the parID field when making an FSSpec to the volume's */
  229.         /* root directory by passing a full pathname in MakeFSSpec's */
  230.         /* fileName parameter. */
  231.         if ( (result == noErr) && (spec->parID == 0) )
  232.             spec->parID = fsRtParID;
  233.     }
  234. #if !SystemSevenOrLater
  235.     else
  236.     {
  237.         Boolean    isDirectory;
  238.         
  239.         result = GetObjectLocation(vRefNum, dirID, fileName,
  240.                                     &(spec->vRefNum), &(spec->parID), spec->name,
  241.                                     &isDirectory);
  242.     }
  243. #endif    /* !SystemSevenOrLater */
  244.     return ( result );
  245. }
  246.  
  247. /*****************************************************************************/
  248.  
  249. pascal    OSErr    FSpOpenDFCompat(const FSSpec *spec,
  250.                                 char permission,
  251.                                 short *refNum)
  252. {
  253. #if !SystemSevenOrLater
  254.     if ( FSHasFSSpecCalls() || QTHasFSSpecCalls() )
  255. #endif    /* !SystemSevenOrLater */
  256.     {
  257.         return ( FSpOpenDF(spec, permission, refNum) );
  258.     }
  259. #if !SystemSevenOrLater
  260.     else
  261.     {
  262.         OSErr            result;
  263.         HParamBlockRec    pb;
  264.         
  265.         pb.ioParam.ioVRefNum = spec->vRefNum;
  266.         pb.fileParam.ioDirID = spec->parID;
  267.         pb.ioParam.ioNamePtr = (StringPtr) &(spec->name);
  268.         pb.ioParam.ioVersNum = 0;
  269.         pb.ioParam.ioPermssn = permission;
  270.         pb.ioParam.ioMisc = NULL;
  271.         result = PBHOpenSync(&pb);    /* OpenDF not supported by System 6, so use Open */
  272.         *refNum = pb.ioParam.ioRefNum;
  273.         return ( result );
  274.     }
  275. #endif    /* !SystemSevenOrLater */
  276. }
  277.  
  278. /*****************************************************************************/
  279.  
  280. pascal    OSErr    FSpOpenRFCompat(const FSSpec *spec,
  281.                                 char permission,
  282.                                 short *refNum)
  283. {
  284. #if !SystemSevenOrLater
  285.     if ( FSHasFSSpecCalls() || QTHasFSSpecCalls() )
  286. #endif    /* !SystemSevenOrLater */
  287.     {
  288.         return ( FSpOpenRF(spec, permission, refNum) );
  289.     }
  290. #if !SystemSevenOrLater
  291.     else
  292.     {
  293.         OSErr            result;
  294.         HParamBlockRec    pb;
  295.         
  296.         pb.ioParam.ioVRefNum = spec->vRefNum;
  297.         pb.fileParam.ioDirID = spec->parID;
  298.         pb.ioParam.ioNamePtr = (StringPtr) &(spec->name);
  299.         pb.ioParam.ioVersNum = 0;
  300.         pb.ioParam.ioPermssn = permission;
  301.         pb.ioParam.ioMisc = NULL;
  302.         result = PBHOpenRFSync(&pb);
  303.         *refNum = pb.ioParam.ioRefNum;
  304.         return ( result );
  305.     }
  306. #endif    /* !SystemSevenOrLater */
  307. }
  308.  
  309. /*****************************************************************************/
  310.  
  311. pascal    OSErr    FSpCreateCompat(const FSSpec *spec,
  312.                                 OSType creator,
  313.                                 OSType fileType,
  314.                                 ScriptCode scriptTag)
  315. {
  316.     OSErr            result;
  317.     UniversalFMPB    pb;
  318.     
  319.     /* There's no conditional to test for, so this test must be made */
  320.     if ( HasFSpCreateScriptSupportFix() )
  321.     {
  322.         return ( FSpCreate(spec, creator, fileType, scriptTag) );
  323.     }
  324.     /*    If FSpCreate isn't called, this code will be executed */
  325.     pb.hPB.fileParam.ioVRefNum = spec->vRefNum;
  326.     pb.hPB.fileParam.ioDirID = spec->parID;
  327.     pb.hPB.fileParam.ioNamePtr = (StringPtr) &(spec->name);
  328.     pb.hPB.fileParam.ioFVersNum = 0;
  329.     result = PBHCreateSync(&(pb.hPB));
  330.     if ( result == noErr )
  331.     {
  332.         /* get info on created item */
  333.         pb.ciPB.hFileInfo.ioFDirIndex = 0;
  334.         result = PBGetCatInfoSync(&(pb.ciPB));
  335.         if ( result == noErr )
  336.         {
  337.             /* Set fdScript in FXInfo */
  338.             /* The negative script constants (smSystemScript, smCurrentScript, and smAllScripts) */
  339.             /* don't make sense on disk, so only use scriptTag if scriptTag >= smRoman */
  340.             /* (smRoman is 0). fdScript is valid if high bit is set (see IM-6, page 9-38) */
  341.             pb.ciPB.hFileInfo.ioFlXFndrInfo.fdScript = (scriptTag >= smRoman) ?
  342.                                                         ((char)scriptTag | (char)0x80) :
  343.                                                         (smRoman);
  344.             /* Set creator/fileType */
  345.             pb.ciPB.hFileInfo.ioFlFndrInfo.fdCreator = creator;
  346.             pb.ciPB.hFileInfo.ioFlFndrInfo.fdType = fileType;
  347.             /* Restore ioDirID field in pb which was changed by PBGetCatInfo */
  348.             pb.ciPB.hFileInfo.ioDirID = spec->parID;
  349.             result = PBSetCatInfoSync(&(pb.ciPB));
  350.         }
  351.     }
  352.     return ( result );
  353. }
  354.  
  355. /*****************************************************************************/
  356.  
  357. pascal    OSErr    FSpDirCreateCompat(const FSSpec *spec,
  358.                                    ScriptCode scriptTag,
  359.                                    long *createdDirID)
  360. {
  361. #if !SystemSevenOrLater
  362.     if ( FSHasFSSpecCalls() || QTHasFSSpecCalls() )
  363. #endif    /* !SystemSevenOrLater */
  364.     {
  365.         return ( FSpDirCreate(spec, scriptTag, createdDirID) );
  366.     }
  367. #if !SystemSevenOrLater
  368.     else
  369.     {
  370.         OSErr            result;
  371.         UniversalFMPB    pb;
  372.         
  373.         pb.hPB.fileParam.ioVRefNum = spec->vRefNum;
  374.         pb.hPB.fileParam.ioDirID = spec->parID;
  375.         pb.hPB.fileParam.ioNamePtr = (StringPtr) &(spec->name);
  376.         result = PBDirCreateSync(&(pb.hPB));
  377.         *createdDirID = pb.hPB.fileParam.ioDirID;
  378.         if ( result == noErr )
  379.         {
  380.             /* get info on created item */
  381.             pb.ciPB.dirInfo.ioFDirIndex = 0;
  382.             pb.ciPB.dirInfo.ioDrDirID = spec->parID;
  383.             result = PBGetCatInfoSync(&(pb.ciPB));
  384.             if ( result == noErr )
  385.             {
  386.                 /* Set frScript in DXInfo */
  387.                 /* The negative script constants (smSystemScript, smCurrentScript, and smAllScripts) */
  388.                 /* don't make sense on disk, so only use scriptTag if scriptTag >= smRoman */
  389.                 /* (smRoman is 0). frScript is valid if high bit is set (see IM-6, page 9-38) */
  390.                 pb.ciPB.dirInfo.ioDrFndrInfo.frScript = (scriptTag >= smRoman) ?
  391.                                                             ((char)scriptTag | (char)0x80) :
  392.                                                             (smRoman);
  393.                 /* Restore ioDirID field in pb which was changed by PBGetCatInfo */
  394.                 pb.ciPB.dirInfo.ioDrDirID = spec->parID;            
  395.                 result = PBSetCatInfoSync(&(pb.ciPB));
  396.             }
  397.         }
  398.         return ( result );
  399.     }
  400. #endif    /* !SystemSevenOrLater */
  401. }
  402.  
  403. /*****************************************************************************/
  404.  
  405. pascal    OSErr    FSpDeleteCompat(const FSSpec *spec)
  406. {
  407. #if !SystemSevenOrLater
  408.     if ( FSHasFSSpecCalls() || QTHasFSSpecCalls() )
  409. #endif    /* !SystemSevenOrLater */
  410.     {
  411.         return ( FSpDelete(spec) );
  412.     }
  413. #if !SystemSevenOrLater
  414.     else
  415.     {
  416.         HParamBlockRec    pb;
  417.         
  418.         pb.ioParam.ioVRefNum = spec->vRefNum;
  419.         pb.fileParam.ioDirID = spec->parID;
  420.         pb.ioParam.ioNamePtr = (StringPtr) &(spec->name);
  421.         pb.ioParam.ioVersNum = 0;
  422.         return ( PBHDeleteSync(&pb) );
  423.     }
  424. #endif    /* !SystemSevenOrLater */
  425. }
  426.  
  427. /*****************************************************************************/
  428.  
  429. pascal    OSErr    FSpGetFInfoCompat(const FSSpec *spec,
  430.                                   FInfo *fndrInfo)
  431. {
  432. #if !SystemSevenOrLater
  433.     if ( FSHasFSSpecCalls() || QTHasFSSpecCalls() )
  434. #endif    /* !SystemSevenOrLater */
  435.     {
  436.         return ( FSpGetFInfo(spec, fndrInfo) );
  437.     }
  438. #if !SystemSevenOrLater
  439.     else
  440.     {
  441.         OSErr            result;
  442.         HParamBlockRec    pb;
  443.         
  444.         pb.fileParam.ioVRefNum = spec->vRefNum;
  445.         pb.fileParam.ioDirID = spec->parID;
  446.         pb.fileParam.ioNamePtr = (StringPtr) &(spec->name);
  447.         pb.fileParam.ioFVersNum = 0;
  448.         pb.fileParam.ioFDirIndex = 0;
  449.         result = PBHGetFInfoSync(&pb);
  450.         *fndrInfo = pb.fileParam.ioFlFndrInfo;
  451.         return ( result );
  452.     }
  453. #endif    /* !SystemSevenOrLater */
  454. }
  455.  
  456. /*****************************************************************************/
  457.  
  458. pascal    OSErr    FSpSetFInfoCompat(const FSSpec *spec,
  459.                                   const FInfo *fndrInfo)
  460. {
  461. #if !SystemSevenOrLater
  462.     if ( FSHasFSSpecCalls() || QTHasFSSpecCalls() )
  463. #endif    /* !SystemSevenOrLater */
  464.     {
  465.         return ( FSpSetFInfo(spec, fndrInfo) );
  466.     }
  467. #if !SystemSevenOrLater
  468.     else
  469.     {
  470.         OSErr            result;
  471.         HParamBlockRec    pb;
  472.         
  473.         pb.fileParam.ioVRefNum = spec->vRefNum;
  474.         pb.fileParam.ioDirID = spec->parID;
  475.         pb.fileParam.ioNamePtr = (StringPtr) &(spec->name);
  476.         pb.fileParam.ioFVersNum = 0;
  477.         pb.fileParam.ioFDirIndex = 0;
  478.         result = PBHGetFInfoSync(&pb);
  479.         if ( result == noErr )
  480.         {
  481.             pb.fileParam.ioFlFndrInfo = *fndrInfo;
  482.             pb.fileParam.ioDirID = spec->parID;
  483.             result = PBHSetFInfoSync(&pb);
  484.         }
  485.         return ( result );
  486.     }
  487. #endif    /* !SystemSevenOrLater */
  488. }
  489.  
  490. /*****************************************************************************/
  491.  
  492. pascal    OSErr    FSpSetFLockCompat(const FSSpec *spec)
  493. {
  494. #if !SystemSevenOrLater
  495.     if ( FSHasFSSpecCalls() || QTHasFSSpecCalls() )
  496. #endif    /* !SystemSevenOrLater */
  497.     {
  498.         return ( FSpSetFLock(spec) );
  499.     }
  500. #if !SystemSevenOrLater
  501.     else
  502.     {
  503.         HParamBlockRec    pb;
  504.         
  505.         pb.fileParam.ioVRefNum = spec->vRefNum;
  506.         pb.fileParam.ioDirID = spec->parID;
  507.         pb.fileParam.ioNamePtr = (StringPtr) &(spec->name);
  508.         pb.fileParam.ioFVersNum = 0;
  509.         return ( PBHSetFLockSync(&pb) );
  510.     }
  511. #endif    /* !SystemSevenOrLater */
  512. }
  513.  
  514. /*****************************************************************************/
  515.  
  516. pascal    OSErr    FSpRstFLockCompat(const FSSpec *spec)
  517. {
  518. #if !SystemSevenOrLater
  519.     if ( FSHasFSSpecCalls() || QTHasFSSpecCalls() )
  520. #endif    /* !SystemSevenOrLater */
  521.     {
  522.         return ( FSpRstFLock(spec) );
  523.     }
  524. #if !SystemSevenOrLater
  525.     else
  526.     {
  527.         HParamBlockRec    pb;
  528.         
  529.         pb.fileParam.ioVRefNum = spec->vRefNum;
  530.         pb.fileParam.ioDirID = spec->parID;
  531.         pb.fileParam.ioNamePtr = (StringPtr) &(spec->name);
  532.         pb.fileParam.ioFVersNum = 0;
  533.         return ( PBHRstFLockSync(&pb) );
  534.     }
  535. #endif    /* !SystemSevenOrLater */
  536. }
  537.  
  538. /*****************************************************************************/
  539.  
  540. pascal    OSErr    FSpRenameCompat(const FSSpec *spec,
  541.                                 ConstStr255Param newName)
  542. {
  543. #if !SystemSevenOrLater
  544.     if ( FSHasFSSpecCalls() || QTHasFSSpecCalls() )
  545. #endif    /* !SystemSevenOrLater */
  546.     {
  547.         return ( FSpRename(spec, newName) );
  548.     }
  549. #if !SystemSevenOrLater
  550.     else
  551.     {
  552.         HParamBlockRec    pb;
  553.         
  554.         pb.ioParam.ioVRefNum = spec->vRefNum;
  555.         pb.fileParam.ioDirID = spec->parID;
  556.         pb.ioParam.ioNamePtr = (StringPtr) &(spec->name);
  557.         pb.ioParam.ioVersNum = 0;
  558.         pb.ioParam.ioMisc = (Ptr) newName;
  559.         return ( PBHRenameSync(&pb) );
  560.     }
  561. #endif    /* !SystemSevenOrLater */
  562. }
  563.  
  564. /*****************************************************************************/
  565.  
  566. pascal    OSErr    FSpCatMoveCompat(const FSSpec *source,
  567.                                  const FSSpec *dest)
  568. {
  569. #if !SystemSevenOrLater
  570.     if ( FSHasFSSpecCalls() || QTHasFSSpecCalls() )
  571. #endif    /* !SystemSevenOrLater */
  572.     {
  573.         return ( FSpCatMove(source, dest) );
  574.     }
  575. #if !SystemSevenOrLater
  576.     else
  577.     {
  578.         CMovePBRec    pb;
  579.         
  580.         /* source and destination volume must be the same */
  581.         if ( source->vRefNum != dest->vRefNum )
  582.             return ( paramErr );
  583.         
  584.         pb.ioNamePtr = (StringPtr) &(source->name);
  585.         pb.ioVRefNum = source->vRefNum;
  586.         pb.ioDirID = source->parID;
  587.         pb.ioNewDirID = dest->parID;
  588.         pb.ioNewName = (StringPtr) &(dest->name);
  589.         return ( PBCatMoveSync(&pb) );
  590.     }
  591. #endif    /* !SystemSevenOrLater */
  592. }
  593.  
  594. /*****************************************************************************/
  595.  
  596. /* GenerateUniqueName generates a name that is unique in both dir1 and dir2 */
  597. /* on the specified volume. Ripped off from Feldman's code. */
  598.  
  599. #if !SystemSevenFiveOrLater
  600. static    OSErr    GenerateUniqueName(short volume,
  601.                                    long *startSeed,
  602.                                    long dir1,
  603.                                    long dir2,
  604.                                    StringPtr uniqueName)
  605. {
  606.     OSErr            error = noErr;
  607.     long            i;
  608.     CInfoPBRec        cinfo;
  609.     unsigned char    hexStr[16];
  610.     
  611.     for ( i = 0; i < 16; ++i )
  612.     {
  613.         if ( i < 10 )
  614.         {
  615.             hexStr[i] = 0x30 + i;
  616.         }
  617.         else
  618.         {
  619.             hexStr[i] = 0x37 + i;
  620.         }
  621.     }
  622.     
  623.     cinfo.hFileInfo.ioVRefNum = volume;
  624.     cinfo.hFileInfo.ioFDirIndex = 0;
  625.     cinfo.hFileInfo.ioNamePtr = uniqueName;
  626.  
  627.     while ( error != fnfErr )
  628.     {
  629.         (*startSeed)++;        
  630.         cinfo.hFileInfo.ioNamePtr[0] = 8;
  631.         for ( i = 1; i <= 8; i++ )
  632.         {
  633.             cinfo.hFileInfo.ioNamePtr[i] = hexStr[((*startSeed >> ((8-i)*4)) & 0xf)];
  634.         }
  635.         cinfo.hFileInfo.ioDirID = dir1;
  636.         error = fnfErr;
  637.         for ( i = 1; i <= 2; i++ )
  638.         {
  639.             error = error & PBGetCatInfoSync(&cinfo);
  640.             cinfo.hFileInfo.ioDirID = dir2;
  641.             if ( (error != fnfErr) && (error != noErr) )
  642.             {
  643.                 return ( error );
  644.             }
  645.         }
  646.     }
  647.     return ( noErr );
  648. }
  649. #endif    /* !SystemSevenFiveOrLater */
  650.  
  651. /*****************************************************************************/
  652.  
  653. pascal    OSErr    FSpExchangeFilesCompat(const FSSpec *source,
  654.                                        const FSSpec *dest)
  655. {
  656. #if !SystemSevenOrLater
  657.     if ( FSHasFSSpecCalls() )
  658. #endif    /* !SystemSevenOrLater */
  659.     {
  660. #if !SystemSevenFiveOrLater
  661.         if ( HasFSpExchangeFilesCompatibilityFix() )
  662. #endif    /* !SystemSevenFiveOrLater */
  663.         {
  664.             return ( FSpExchangeFiles(source, dest) );
  665.         }
  666.     }
  667. #if !SystemSevenFiveOrLater
  668.     /*    If FSpExchangeFiles isn't called, this code will be executed */
  669.     {
  670.         HParamBlockRec            pb;
  671.         CInfoPBRec                catInfoSource, catInfoDest;
  672.         OSErr                    result, result2;
  673.         Str31                    unique1, unique2;
  674.         StringPtr                unique1Ptr, unique2Ptr, swapola;
  675.         GetVolParmsInfoBuffer    volInfo;
  676.         long                    theSeed, temp;
  677.         
  678.         /* Make sure the source and destination are on the same volume */
  679.         if ( source->vRefNum != dest->vRefNum )
  680.         {
  681.             result = diffVolErr;
  682.             goto errorExit3;
  683.         }
  684.         
  685.         /* Try PBExchangeFiles first since it preserves the file ID reference */
  686.         pb.fidParam.ioNamePtr = (StringPtr) &(source->name);
  687.         pb.fidParam.ioVRefNum = source->vRefNum;
  688.         pb.fidParam.ioDestNamePtr = (StringPtr) &(dest->name);
  689.         pb.fidParam.ioDestDirID = dest->parID;
  690.         pb.fidParam.ioSrcDirID = source->parID;
  691.     
  692.         result = PBExchangeFilesSync(&pb);
  693.     
  694.         /* Note: The compatibility case won't work for files with *Btree control blocks. */
  695.         /* Right now the only *Btree files are created by the system. */
  696.         if ( result != noErr )
  697.         {
  698.             pb.ioParam.ioNamePtr = NULL;
  699.             pb.ioParam.ioBuffer = (Ptr) &volInfo;
  700.             pb.ioParam.ioReqCount = sizeof(volInfo);
  701.             result2 = PBHGetVolParmsSync(&pb);
  702.             
  703.             /* continue if volume has no fileID support (or no GetVolParms support) */
  704.             if ( (result2 == noErr) && hasFileIDs(volInfo) )
  705.             {
  706.                 goto errorExit3;
  707.             }
  708.     
  709.             /* Get the catalog information for each file */
  710.             /* and make sure both files are *really* files */
  711.             catInfoSource.hFileInfo.ioVRefNum = source->vRefNum;
  712.             catInfoSource.hFileInfo.ioFDirIndex = 0;
  713.             catInfoSource.hFileInfo.ioNamePtr = (StringPtr) &(source->name);
  714.             catInfoSource.hFileInfo.ioDirID = source->parID;
  715.             catInfoSource.hFileInfo.ioACUser = 0; /* ioACUser used to be filler2 */
  716.             result = PBGetCatInfoSync(&catInfoSource);
  717.             if ( result != noErr )
  718.             {
  719.                 goto errorExit3;
  720.             }
  721.             if ( (catInfoSource.hFileInfo.ioFlAttrib & ioDirMask) != 0 )
  722.             {
  723.                 result = notAFileErr;
  724.                 goto errorExit3;
  725.             }
  726.             
  727.             catInfoDest.hFileInfo.ioVRefNum = dest->vRefNum;
  728.             catInfoDest.hFileInfo.ioFDirIndex = 0;
  729.             catInfoDest.hFileInfo.ioNamePtr = (StringPtr) &(dest->name);
  730.             catInfoDest.hFileInfo.ioDirID = dest->parID;
  731.             catInfoDest.hFileInfo.ioACUser = 0; /* ioACUser used to be filler2 */
  732.             result = PBGetCatInfoSync(&catInfoDest);
  733.             if ( result != noErr )
  734.             {
  735.                 goto errorExit3;
  736.             }
  737.             if ( (catInfoDest.hFileInfo.ioFlAttrib & ioDirMask) != 0 )
  738.             {
  739.                 result = notAFileErr;
  740.                 goto errorExit3;
  741.             }
  742.             
  743.             /* generate 2 filenames that are unique in both directories */
  744.             theSeed = 0x64666A6C;    /* a fine unlikely filename */
  745.             unique1Ptr = (StringPtr)&unique1;
  746.             unique2Ptr = (StringPtr)&unique2;
  747.             
  748.             result = GenerateUniqueName(source->vRefNum, &theSeed, source->parID, dest->parID, unique1Ptr);
  749.             if ( result != noErr )
  750.             {
  751.                 goto errorExit3;
  752.             }
  753.     
  754.             GenerateUniqueName(source->vRefNum, &theSeed, source->parID, dest->parID, unique2Ptr);
  755.             if ( result != noErr )
  756.             {
  757.                 goto errorExit3;
  758.             }
  759.     
  760.             /* rename source to unique1 */
  761.             pb.fileParam.ioNamePtr = (StringPtr) &(source->name);
  762.             pb.ioParam.ioMisc = (Ptr) unique1Ptr;
  763.             pb.ioParam.ioVersNum = 0;
  764.             result = PBHRenameSync(&pb);
  765.             if ( result != noErr )
  766.             {
  767.                 goto errorExit3;
  768.             }
  769.             
  770.             /* rename dest to unique2 */
  771.             pb.ioParam.ioMisc = (Ptr) unique2Ptr;
  772.             pb.ioParam.ioVersNum = 0;
  773.             pb.fileParam.ioNamePtr = (StringPtr) &(dest->name);
  774.             pb.fileParam.ioDirID = dest->parID;
  775.             result = PBHRenameSync(&pb);
  776.             if ( result != noErr )
  777.             {
  778.                 goto errorExit2;    /* back out gracefully by renaming unique1 back to source */
  779.             }
  780.                 
  781.             /* If files are not in same directory, swap their locations */
  782.             if ( source->parID != dest->parID )
  783.             {
  784.                 /* move source file to dest directory */
  785.                 pb.copyParam.ioNamePtr = unique1Ptr;
  786.                 pb.copyParam.ioNewName = NULL;
  787.                 pb.copyParam.ioNewDirID = dest->parID;
  788.                 pb.copyParam.ioDirID = source->parID;
  789.                 result = PBCatMoveSync((CMovePBPtr) &pb);
  790.                 if ( result != noErr )
  791.                 {
  792.                     goto errorExit1;    /* back out gracefully by renaming both files to original names */
  793.                 }
  794.                 
  795.                 /* move dest file to source directory */
  796.                 pb.copyParam.ioNamePtr = unique2Ptr;
  797.                 pb.copyParam.ioNewDirID = source->parID;
  798.                 pb.copyParam.ioDirID = dest->parID;
  799.                 result = PBCatMoveSync((CMovePBPtr) &pb);
  800.                 if ( result != noErr)
  801.                 {
  802.                     /* life is very bad.  We'll at least try to move source back */
  803.                     pb.copyParam.ioNamePtr = unique1Ptr;
  804.                     pb.copyParam.ioNewName = NULL;
  805.                     pb.copyParam.ioNewDirID = source->parID;
  806.                     pb.copyParam.ioDirID = dest->parID;
  807.                     (void) PBCatMoveSync((CMovePBPtr) &pb);    /* ignore errors */
  808.                     goto errorExit1;    /* back out gracefully by renaming both files to original names */
  809.                 }
  810.             }
  811.             
  812.             /* Make unique1Ptr point to file in source->parID */
  813.             /* and unique2Ptr point to file in dest->parID */
  814.             /* This lets us fall through to the rename code below */
  815.             swapola = unique1Ptr;
  816.             unique1Ptr = unique2Ptr;
  817.             unique2Ptr = swapola;
  818.     
  819.             /* At this point, the files are in their new locations (if they were moved) */
  820.             /* Source is named Unique1 (name pointed to by unique2Ptr) and is in dest->parID */
  821.             /* Dest is named Unique2 (name pointed to by unique1Ptr) and is in source->parID */
  822.             /* Need to swap attributes except mod date and swap names */
  823.     
  824.             /* swap the catalog info by re-aiming the CInfoPB's */
  825.             catInfoSource.hFileInfo.ioNamePtr = unique1Ptr;
  826.             catInfoDest.hFileInfo.ioNamePtr = unique2Ptr;
  827.             
  828.             catInfoSource.hFileInfo.ioDirID = source->parID;
  829.             catInfoDest.hFileInfo.ioDirID = dest->parID;
  830.             
  831.             /* Swap the original mod dates with each file */
  832.             temp = catInfoSource.hFileInfo.ioFlMdDat;
  833.             catInfoSource.hFileInfo.ioFlMdDat = catInfoDest.hFileInfo.ioFlMdDat;
  834.             catInfoDest.hFileInfo.ioFlMdDat = temp;
  835.             
  836.             /* Here's the swap (ignore errors) */
  837.             (void) PBSetCatInfoSync(&catInfoSource); 
  838.             (void) PBSetCatInfoSync(&catInfoDest);
  839.             
  840.             /* rename unique2 back to dest */
  841. errorExit1:
  842.             pb.ioParam.ioMisc = (Ptr) &(dest->name);
  843.             pb.ioParam.ioVersNum = 0;
  844.             pb.fileParam.ioNamePtr = unique2Ptr;
  845.             pb.fileParam.ioDirID = dest->parID;
  846.             (void) PBHRenameSync(&pb);    /* ignore errors */
  847.     
  848.             /* rename unique1 back to source */
  849. errorExit2:
  850.             pb.ioParam.ioMisc = (Ptr) &(source->name);
  851.             pb.ioParam.ioVersNum = 0;
  852.             pb.fileParam.ioNamePtr = unique1Ptr;
  853.             pb.fileParam.ioDirID = source->parID;
  854.             (void) PBHRenameSync(&pb); /* ignore errors */
  855.         }
  856. errorExit3: { /* null statement */ }
  857.         return ( result );
  858.     }
  859. #endif    /* !SystemSevenFiveOrLater */
  860. }
  861.  
  862. /*****************************************************************************/
  863.  
  864. /* 
  865. **    Resource Manager FSp calls
  866. */
  867.  
  868. /*****************************************************************************/
  869.  
  870. pascal    short    FSpOpenResFileCompat(const FSSpec *spec,
  871.                                      SignedByte permission)
  872. {
  873. #if !SystemSevenOrLater
  874.     if ( FSHasFSSpecCalls() || QTHasFSSpecCalls() )
  875. #endif    /* !SystemSevenOrLater */
  876.     {
  877.         return ( FSpOpenResFile(spec, permission) );
  878.     }
  879. #if !SystemSevenOrLater
  880.     else
  881.     {
  882.         return ( HOpenResFile(spec->vRefNum, spec->parID, spec->name, permission) );
  883.     }
  884. #endif    /* !SystemSevenOrLater */
  885. }
  886.  
  887. /*****************************************************************************/
  888.  
  889. pascal    void    FSpCreateResFileCompat(const FSSpec *spec,
  890.                                        OSType creator,
  891.                                        OSType fileType,
  892.                                        ScriptCode scriptTag)
  893. {    
  894.     if ( HasFSpCreateScriptSupportFix() )
  895.     {
  896.         FSpCreateResFile(spec, creator, fileType, scriptTag);
  897.         return;
  898.     }
  899.     /*    If FSpCreateResFile isn't called, this code will be executed */
  900.     {
  901.         OSErr            result;
  902.         CInfoPBRec        pb;
  903.         
  904.         HCreateResFile(spec->vRefNum, spec->parID, spec->name);
  905.         if ( ResError() == noErr )
  906.         {
  907.             /* get info on created item */
  908.             pb.hFileInfo.ioVRefNum = spec->vRefNum;
  909.             pb.hFileInfo.ioDirID = spec->parID;
  910.             pb.hFileInfo.ioNamePtr = (StringPtr) &(spec->name);
  911.             pb.hFileInfo.ioFDirIndex = 0;
  912.             result = PBGetCatInfoSync(&pb);
  913.             if ( result == noErr )
  914.             {
  915.                 /* Set fdScript in FXInfo */
  916.                 /* The negative script constants (smSystemScript, smCurrentScript, and smAllScripts) */
  917.                 /* don't make sense on disk, so only use scriptTag if scriptTag >= smRoman */
  918.                 /* (smRoman is 0). fdScript is valid if high bit is set (see IM-6, page 9-38) */
  919.                 pb.hFileInfo.ioFlXFndrInfo.fdScript = (scriptTag >= smRoman) ?
  920.                                                         ((char)scriptTag | (char)0x80) :
  921.                                                         (smRoman);
  922.                 /* Set creator/fileType */
  923.                 pb.hFileInfo.ioFlFndrInfo.fdCreator = creator;
  924.                 pb.hFileInfo.ioFlFndrInfo.fdType = fileType;
  925.                 
  926.                 /* Restore ioDirID field in pb which was changed by PBGetCatInfo */
  927.                 pb.hFileInfo.ioDirID = spec->parID;
  928.                 result = PBSetCatInfoSync(&pb);
  929.             }
  930.             /* Set ResErr low memory global to result */
  931.             LMSetResErr(result);
  932.         }
  933.         return;
  934.     }
  935. }
  936.  
  937. /*****************************************************************************/
  938.